/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package tletlis.model;

import java.awt.Color;
import java.awt.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;

import tletlis.UI.GUI;
import tletlis.view.GamePanel;

/**
 * A class that represents the area where the bricks are shown on the
 * GUI.
 * @author Gustav
 */
public class Area {


    private RowList rowList;

    //Height and width of the area
    private int height;
    private int width;

    private int row;

    private int nr;

    private AbstractBrick brick;
    private AbstractBrick nextBrick;

    private GUI gui;

    private GamePanel gamePanel;

    public static enum BrickEvent {DOWN,LEFT,RIGHT,ALLDOWN,ROTATE};

    private boolean isRotate = false;
    /**
     * Contructor initializing an area
     * @param width The width of the area in pixels
     * @param The number of horizontal positions the area will contain
     * @param height The height of the area in pixels
     */
    public Area(int width, int nr, int height) {

        row = 0;

        Position.setLength(width/nr);

        gui = new GUI();

        gamePanel = new GamePanel(width,height,gui.getGameBoard(),gui.getNextBrickPanel());

        this.width = width;
        this.height = height;
        this.nr = nr;
        nextBrick = newBrick();

        if(width%nr != 0 || height%nr != 0){
            //TODO Hantering av fel
        }
        rowList = new RowList(height/Position.getLength(),(width/Position.getLength()));

        gamePanel.drawAllGameBoard(rowList);


    }
    /**
     *
     * @return returns a list with components from the GUI
     */
    public List<Component> getComps() {
        return gui.getComps();
    }
    /**
     *
     * @param name Sets name of the player on the GUI
     */
    public void setName(String name) {
        gui.setName(name);
    }
    /**
     *
     * @param name Sets the oponents name on the GUI
     */
    public void setOponentName(String name) {
        gui.setOponentName(name);
    }
    /**
     *
     * @param ip Sets the computers ip on the GUI
     */
    public void setIpLabel(String ip){
        gui.setIpLabel(ip);
    }
    /**
     * Updates the score on the GUI
     * @param score The score
     * @param totRows The total number of rows
     */
    public void updateScore(int score, int totRows) {
        gui.updateScore(score, totRows);
    }
    /**
     * Updates the opponents score on the GUI
     * @param score The score
     * @param totRows The total number of rows
     */
    public void updateOponentScore(int score, int totRows){
        gui.updateOponentScore(score, totRows);
    }

    public void win() {
        gamePanel.win();
    }
    // Returns a random brick in start position
    private AbstractBrick newBrick() {

        int rnd = (int)(Math.random()*7);

        switch(rnd) {
            case 0:
                return new YellowBrick(0,width/2);
            case 1:
                return new TurquoiseBrick(0,width/2);
            case 2:
                return new OrangeBrick(0,width/2);
            case 3:
                return new LilacBrick(0,width/2);
            case 4:
                return new RedBrick(0,width/2);
            case 5:
                return new GreenBrick(0,width/2);
            case 6:
                return new BlueBrick(0,width/2);
        }
        return new YellowBrick(0,width/2);
    }
    /**
     * Updates the gameboard
     * @param event Tells in what to do with the brick ( move left,right,down or rotate)
     * @param nr The number of rows cleared from the oponent, should be zero if singleplayer
     * @return Returns the number of rows cleared
     */
    public synchronized int update(BrickEvent event, int nr) {
        int rows = 0;
        if(event == BrickEvent.ROTATE) {
            isRotate = true;
        }
        else {
            isRotate = false;
        }
        if(nr > 0) {

            moveUp();
            for(int i = 0; i < nr; i++)
                gamePanel.removeRow(rowList.removeLast(), Color.GRAY);

        }

        int brickTop;



        boolean moved = false;

        if(brick == null) {
            row = 0;
            brick = newBrick();

            gamePanel.drawGameBoard(brick.getCords(), brick.color);

            gamePanel.drawNextBrickPanel(nextBrick.getCords(), nextBrick.color);
            
            
            return rows;
        }

        
        clearBrick(brick.getCords());
        gamePanel.drawGameBoard(brick.getCords(), Color.BLACK);
        


        if(event == BrickEvent.DOWN || event == BrickEvent.ROTATE) {
            moved = setGamePos(brick.moveBrick(event),brick.color);

        }
        else if(event == BrickEvent.RIGHT  || event == BrickEvent.LEFT) {
            boolean OkToMove = true;

            for(Position p: brick.getCords()) {
                if(p.getX() <= 0 && event == BrickEvent.LEFT) {
                    OkToMove = false;
                }
                if(p.getX() >= width-Position.getLength() && event == BrickEvent.RIGHT) {
                     OkToMove = false;
                }
            }
            if(OkToMove) {
                moved = setGamePos(brick.moveBrick(event),brick.color);
            }
        }

        else {
            while(true) {
                if(!setGamePos(brick.moveBrick(BrickEvent.DOWN),brick.color))
                    break;
                else
                    clearBrick(brick.getCords());
            }
        }
        if(!moved || event == BrickEvent.ALLDOWN) {

            for(Position p:brick.getCords())
                setGamePos(p,brick.color);



            gamePanel.drawGameBoard(brick.getCords(), brick.color);
            if(event == BrickEvent.ALLDOWN || event == BrickEvent.DOWN) {
                brickTop = brick.getTopX();

                brick = nextBrick;

                nextBrick = newBrick();
                gamePanel.drawNextBrickPanel(nextBrick.getCords(), nextBrick.color);
                for(int i = brickTop; i < rowList.getRowList().size(); i++) {
                    if(isRow(i)) {
                        rows++;

                    }
                }
                
                for(Position p: brick.getCords()) {
                    gamePanel.drawGameBoard(p, brick.color);
                    if(!(rowList.getPosition(p).isFree())) {
                        gamePanel.gameOver();
                        return -1;
                    }
                
            }
                

        }


        }

        clearBrick(brick.getCords());
        gamePanel.drawGameBoard(brick.getCords(), brick.color);
        return rows;

    }


    private void clear(Position p) {
        try {
            rowList.getPosition(p).clear();
            gamePanel.drawGameBoard(p, Color.BLACK);
        }
        catch(IndexOutOfBoundsException e) {

        }

    }

    private void clearBrick(List<Position> lp) {
        for(Position p: lp)
            clear(p);
    }
    private void clear(List<GamePosition> posList) {
        for(GamePosition g:posList) {
            clear(g);
        }
    }



    private void setGamePos(Position p, Color c) {

        try {
            rowList.getPosition(p).set(c);
            gamePanel.drawGameBoard(p, c);
        }catch(NoSuchElementException e){

        }
        catch(IndexOutOfBoundsException e) {

        }

    }

    private boolean setGamePos(List<Position> lp, Color c) {
        if(controlbounds(lp)) {
            for(Position p: lp)
                setGamePos(p,c);
            brick.setBrick(lp,isRotate);
            return true;
        }
        return false;
    }

    private boolean controlbounds(List<Position> pos) {

        GamePosition temp;
        for(Position p:pos) {

            try {
                temp = rowList.getPosition(p);

                if(!temp.isFree()) {

                    return false;
                }

            }
            catch(NoSuchElementException e) {

                return false;
            }
            catch(IndexOutOfBoundsException e) {

                return false;
            }
        }
        return true;
    }

    private boolean isRow(int n) {

        Row tempRow = rowList.getRowList().get(n);
        for(GamePosition g :tempRow.getGamePosList()) {
            if(g.isFree())
                return false;
        }
        clear(tempRow.getGamePosList());
        for(int i = n; i > 0; i-- ) {
            List<GamePosition> tempList = rowList.getRowList().get(i).getGamePosList();
            List<GamePosition> nextRowList = rowList.getRowList().get(i-1).getGamePosList();

            for(int j = 0; j < (tempList.size()); j++) {
                GamePosition g = tempList.get(j);
                GamePosition p = nextRowList.get(j);

                    g.set(p.getColor());
                    gamePanel.drawGameBoard(g, g.getColor());

            }
        }
        clear(rowList.getRowList().get(0).getGamePosList());

        return true;
    }

    private void moveUp() {

        for(int i = 0 ; i < rowList.getRowList().size()-1; i++) {
            List<GamePosition> temp = rowList.getRowList().get(i).getGamePosList();
            List<GamePosition> nextRow = rowList.getRowList().get(i+1).getGamePosList();
            for(int j = 0; j < temp.size(); j++) {
                GamePosition g = temp.get(j);
                GamePosition p = nextRow.get(j);

                g.set(p.getColor());
                gamePanel.drawGameBoard(g, g.getColor());
            }

        }
    }


}
